package jam4j.lang;

import jam4j.build.Target;

final class Rule {
    private final String name;
    private ActionDef actionDef;
    private Procedure procedure;
    
    Rule(String name) {
        this(name, null, null);
    }
    
    Rule(String name, Procedure procedure) {
        this(name, procedure, null);
    }
    
    Rule(String name, ActionDef actionDef) {
        this(name, null, actionDef);
    }
    
    Rule(String name, Procedure procedure, ActionDef actionDef) {
        this.name = name;
        this.procedure = procedure;
        this.actionDef = actionDef;
    }
    
    String name() { return name; }
    
    String[] call(Context cxt, Target onTgt, String[] ... args) {
        if (actionDef != null && args.length > 0) {
            final Target[] targets = cxt.targets(args[0]);
            final Target[] sourceTargets =
                args.length == 1 ? new Target[0] : cxt.targets(args[1]);
            
            Target.addActionToTargets(actionDef, targets, sourceTargets);
        }
        
        Statement.logExec("%s\n", name);
        Statement.increaseStackDepth();
        try {
            return procedure == null ?
                    Expression.UNDEF : procedure.call(cxt, onTgt, args);
        } finally {
            Statement.decreaseStackDepth();
        }
    }
    
    void setProcedure(Procedure procedure) {
        this.procedure = procedure;
    }
    
    void setAction(ActionDef actionDef) {
        this.actionDef = actionDef;
    }
    
    public String toString() {
        final StringBuilder builder =
            new StringBuilder("Rule \u201c")
                .append(name)
                .append("\u201d [");
        
        if (procedure != null) {
            builder.append("procedure=").append(procedure);
            if (actionDef != null)
                builder.append(' ');
        }
        
        if (actionDef != null)
            builder.append("actionDef=").append(actionDef);
        
        return builder.append(']').toString();
    }

    void defineAction(Expression body, int maxLineLength,
            String[] boundVariables,
            ActionDef.Modifier[] modifiers) {
        setAction(new ActionDef(
                this, body, maxLineLength, boundVariables, modifiers));
    }
}
